/*
 * bsp_pwm.c
 *
 *  Created on: 2025 Jan 23
 *      Author: SFLY
 */
#include "bsp_pwm.h"
#include "bsp_board_config.h"
void Bsp_SYNC_Init(void)
{
   SysCtl_setSyncOutputConfig(SYSCTL_SYNC_OUT_SRC_EPWM1SYNCOUT);
   SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
   SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM7, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
}

void Bsp_EPWM_GPIO_Init(void)
{
    // EPWM1A->UH
       GPIO_setPinConfig(GPIO_0_EPWM1_A);
       GPIO_setDirectionMode(EPWM1_A_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM1_A_GPIO, GPIO_PIN_TYPE_STD);

       // EPWM1B->UL
       GPIO_setPinConfig(GPIO_1_EPWM1_B);
       GPIO_setDirectionMode(EPWM1_B_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM1_B_GPIO, GPIO_PIN_TYPE_STD);

       // EPWM2A->VH
       GPIO_setPinConfig(GPIO_2_EPWM2_A);
       GPIO_setDirectionMode(EPWM2_A_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM2_A_GPIO, GPIO_PIN_TYPE_STD);

       // EPWM2B->VL
       GPIO_setPinConfig(GPIO_3_EPWM2_B);
       GPIO_setDirectionMode(EPWM2_B_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM2_B_GPIO, GPIO_PIN_TYPE_STD);

       // EPWM3A->WH
       GPIO_setPinConfig(GPIO_4_EPWM3_A);
       GPIO_setDirectionMode(EPWM3_A_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM3_A_GPIO, GPIO_PIN_TYPE_STD);

       // EPWM3B->WL
       GPIO_setPinConfig(GPIO_5_EPWM3_B);
       GPIO_setDirectionMode(EPWM3_B_GPIO, GPIO_DIR_MODE_OUT);
       GPIO_setPadConfig(EPWM3_B_GPIO, GPIO_PIN_TYPE_STD);
}

void Bsp_EPWM_Init(void)
{
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
    DEVICE_DELAY_US(100U);

    uint16_t PWMPeriod          = (uint16_t)((DEVICE_SYSCLK_FREQ / MOTOR_SYS_PWM_SWITCHING_FREQ_HZ) / 2);
    uint16_t DeadTimeClk        = (uint16_t)(MOTOR_SYS_PWM_DEAD_TIME_NS * DEVICE_SYSCLK_FREQ_MHZ / 1000);
    // disable the ePWM module time base clock sync signal
    // to synchronize all of the PWMs
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM3);
    setupPWMs(EPWM1_BASE, PWMPeriod, DeadTimeClk);
    setupPWMs(EPWM2_BASE, PWMPeriod, DeadTimeClk);
    setupPWMs(EPWM3_BASE, PWMPeriod, DeadTimeClk);
    PWMtriggerADC(EPWM1_BASE, USER_NUM_PWM_TICKS_PER_ISR_TICK);
    //
    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
}

void setupPWMs(uint32_t PWMBase, uint16_t PWMPeriod, uint16_t DeadTimeClk) {
    // setup the Time-Base Control Register (TBCTL)
       EPWM_setTimeBaseCounterMode(PWMBase, EPWM_COUNTER_MODE_UP_DOWN);
       EPWM_disablePhaseShiftLoad(PWMBase);
       EPWM_setPeriodLoadMode(PWMBase, EPWM_PERIOD_DIRECT_LOAD);
       EPWM_setSyncOutPulseMode(PWMBase, EPWM_SYNC_OUT_PULSE_ON_SOFTWARE);
       EPWM_setClockPrescaler(PWMBase, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
       EPWM_setCountModeAfterSync(PWMBase, EPWM_COUNT_MODE_UP_AFTER_SYNC);
       EPWM_setEmulationMode(PWMBase, EPWM_EMULATION_FREE_RUN);

       // setup the Timer-Based Phase Register (TBPHS)
       EPWM_setPhaseShift(PWMBase, 0);

       // setup the Time-Base Counter Register (TBCTR)
       EPWM_setTimeBaseCounter(PWMBase, 0);

       // setup the Time-Base Period Register (TBPRD)
       // set to zero initially
       EPWM_setTimeBasePeriod(PWMBase, 0);

       // setup the Counter-Compare Control Register (CMPCTL)
       EPWM_setCounterCompareShadowLoadMode(PWMBase, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);

       // setup the Action-Qualifier Output A Register (AQCTLA)
       EPWM_setActionQualifierAction(PWMBase, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
       EPWM_setActionQualifierAction(PWMBase, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);

       // setup the Action-Qualifier Output A Register (AQCTLB)
       EPWM_setActionQualifierAction(PWMBase, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
       EPWM_setActionQualifierAction(PWMBase, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);

       // setup the Dead-Band Generator Control Register (DBCTL)
       EPWM_setDeadBandDelayMode(PWMBase, EPWM_DB_RED, true);
       EPWM_setDeadBandDelayMode(PWMBase, EPWM_DB_FED, true);

       // select EPWMA as the input to the dead band generator
       EPWM_setRisingEdgeDeadBandDelayInput(PWMBase, EPWM_DB_INPUT_EPWMA);

       // configure the right polarity for active high complementary config.
       EPWM_setDeadBandDelayPolarity(PWMBase, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
       EPWM_setDeadBandDelayPolarity(PWMBase, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);

       // setup the PWM-Chopper Control Register (PCCTL)
       EPWM_disableChopper(PWMBase);

       // setup the Trip Zone Select Register (TZSEL)
       EPWM_disableTripZoneSignals(PWMBase,
                                   EPWM_TZ_SIGNAL_CBC1 |
                                   EPWM_TZ_SIGNAL_CBC2 |
                                   EPWM_TZ_SIGNAL_CBC3 |
                                   EPWM_TZ_SIGNAL_CBC4 |
                                   EPWM_TZ_SIGNAL_CBC5 |
                                   EPWM_TZ_SIGNAL_CBC6 |
                                   EPWM_TZ_SIGNAL_DCAEVT2 |
                                   EPWM_TZ_SIGNAL_DCBEVT2 |
                                   EPWM_TZ_SIGNAL_OSHT1 |
                                   EPWM_TZ_SIGNAL_OSHT2 |
                                   EPWM_TZ_SIGNAL_OSHT3 |
                                   EPWM_TZ_SIGNAL_OSHT4 |
                                   EPWM_TZ_SIGNAL_OSHT5 |
                                   EPWM_TZ_SIGNAL_OSHT6 |
                                   EPWM_TZ_SIGNAL_DCAEVT1 |
                                   EPWM_TZ_SIGNAL_DCBEVT1);

       // since the PWM is configured as an up/down counter, the period register is
       // set to one-half of the desired PWM period
       EPWM_setTimeBasePeriod(PWMBase, PWMPeriod);
       EPWM_setCounterCompareValue(PWMBase, EPWM_COUNTER_COMPARE_A, PWMPeriod / 2);

       EPWM_setRisingEdgeDeadBandDelayInput(PWMBase, EPWM_DB_INPUT_EPWMA);
       EPWM_setFallingEdgeDeadBandDelayInput(PWMBase, EPWM_DB_INPUT_EPWMB);
       EPWM_setDeadBandDelayMode(PWMBase, EPWM_DB_RED, true);
       EPWM_setDeadBandDelayMode(PWMBase, EPWM_DB_FED, true);
       EPWM_setRisingEdgeDelayCountShadowLoadMode(PWMBase, EPWM_RED_LOAD_ON_CNTR_ZERO_PERIOD);
       EPWM_setFallingEdgeDelayCountShadowLoadMode(PWMBase, EPWM_FED_LOAD_ON_CNTR_ZERO_PERIOD);
       EPWM_setRisingEdgeDelayCount(PWMBase, DeadTimeClk);
       EPWM_setFallingEdgeDelayCount(PWMBase, DeadTimeClk);
}
void PWMtriggerADC(uint32_t PWMBase, uint16_t numPWMTicksPerISRTick) {
    // setup the Event Trigger Selection Register (ETSEL)
       EPWM_disableInterrupt(PWMBase);
       EPWM_setADCTriggerSource(PWMBase, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPC);//EPWM_SOC_TBCTR_D_CMPC);

       // setup the Event Trigger Prescale Register (ETPS)
       if(numPWMTicksPerISRTick > 15) {
           EPWM_setInterruptEventCount(PWMBase, 15);
           EPWM_setADCTriggerEventPrescale(PWMBase, EPWM_SOC_A, 15);
       } else if(numPWMTicksPerISRTick < 1) {
           EPWM_setInterruptEventCount(PWMBase, 1);
           EPWM_setADCTriggerEventPrescale(PWMBase, EPWM_SOC_A, 1);
       } else {
           EPWM_setInterruptEventCount(PWMBase, numPWMTicksPerISRTick);
           EPWM_setADCTriggerEventPrescale(PWMBase, EPWM_SOC_A, 1);
       }

       // setup the Event Trigger Clear Register (ETCLR)
       EPWM_clearADCTriggerFlag(PWMBase, EPWM_SOC_A);
       EPWM_enableADCTrigger(PWMBase, EPWM_SOC_A);
       // write the PWM data value  for ADC trigger
       EPWM_setCounterCompareValue(PWMBase, EPWM_COUNTER_COMPARE_C, 2);
}

/**
 ******************************************************************************
 ** \brief enable/disable output PWM
 **
 ** \param [in] none
 **
 ** \retval     none
 ******************************************************************************/
void Init_EnMotorPwm(int bEnable) {
    if (TRUE == bEnable) {
        EPwm1Regs.AQCSFRC.all = 0x00;
        EPwm2Regs.AQCSFRC.all = 0x00;
        EPwm3Regs.AQCSFRC.all = 0x00;
    } else {
        EPwm1Regs.AQCSFRC.all = 0x09;
        EPwm2Regs.AQCSFRC.all = 0x09;
        EPwm3Regs.AQCSFRC.all = 0x09;
    }
}

void MotorPWM_SetUVWDuty(uint32_t DutyU,uint32_t DutyV,uint32_t DutyW) {
    EPwm1Regs.CMPA.bit.CMPA = EPwm1Regs.TBPRD - DutyU;
    EPwm2Regs.CMPA.bit.CMPA = EPwm2Regs.TBPRD  - DutyV;
    EPwm3Regs.CMPA.bit.CMPA = EPwm3Regs.TBPRD  - DutyW;
}

void MotorPWM_SetUVWDuty_Zero(void) {
    EPwm1Regs.CMPA.bit.CMPA = EPwm1Regs.TBPRD ;
    EPwm2Regs.CMPA.bit.CMPA = EPwm2Regs.TBPRD ;
    EPwm3Regs.CMPA.bit.CMPA = EPwm3Regs.TBPRD ;
}


uint16_t Motor_GetPWMMaxCount(void)
{
    uint16_t PeakCnt= EPwm1Regs.TBPRD;
    return PeakCnt;
}
